﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EscPrinterVfpV1d0.Service
{
    public class TMU220PrinterCmdUtilsV1d0
    {

        public const byte ESC = 27;    // 换码
        public const byte FS = 28;    // 文本分隔符
        public const byte GS = 29;    // 组分隔符
        public const byte DLE = 16;    // 数据连接换码
        public const byte EOT = 4;    // 传输结束
        public const byte ENQ = 5;    // 询问字符
        public const byte SP = 32;    // 空格
        public const byte HT = 9;    // 横向列表
        public const byte LF = 10;    // 打印并换行（水平定位）
        public const byte CR = 13;    // 归位键
        public const byte FF = 12;    // 走纸控制（打印并回到标准模式（在页模式下） ）
        public const byte CAN = 24;    // 作废（页模式下取消打印数据 ）
        /**
         * 打印纸一行最大的字节
         */
        private const int LINE_BYTE_SIZE = 32;
        /**
         * 分隔符
         */
        private const String SEPARATOR = "$";
        private static StringBuilder sb = new StringBuilder();

        /**
         * 打印机初始化
         * 
         * @return
         */
        public static byte[] init_printer()
        {
            byte[] result = new byte[2];
            result[0] = ESC;
            result[1] = 64;
            return result;
        }
        /**
         * 打开钱箱
         * 
         * @return
         */
        public static byte[] open_money()
        {
            byte[] result = new byte[5];
            result[0] = ESC;
            result[1] = 112;
            result[2] = 48;
            result[3] = 64;
            result[4] = 0;
            return result;
        }

        /**
         * 换行
         * 
         * @param lineNum要换几行
         * @return
         */
        public static byte[] nextLine(int lineNum)
        {
            byte[] result = new byte[lineNum];
            for (int i = 0; i < lineNum; i++)
            {
                result[i] = LF;
            }

            return result;
        }


        /**
         * 绘制下划线（1点宽）
         * 
         * @return
         */
        public static byte[] underlineWithOneDotWidthOn()
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 45;
            result[2] = 1;
            return result;
        }

        /**
         * 绘制下划线（2点宽）
         * 
         * @return
         */
        public static byte[] underlineWithTwoDotWidthOn()
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 45;
            result[2] = 2;
            return result;
        }

        /**
         * 取消绘制下划线
         * 
         * @return
         */
        public static byte[] underlineOff()
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 45;
            result[2] = 0;
            return result;
        }


        /**
         * 选择加粗模式
         * 
         * @return
         */
        public static byte[] boldOn()
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 69;
            result[2] = 0xF;
            return result;
        }

        /**
         * 取消加粗模式
         * 
         * @return
         */
        public static byte[] boldOff()
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 69;
            result[2] = 0;
            return result;
        }


        /**
         * 左对齐
         * 
         * @return
         */
        public static byte[] alignLeft()
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 97;
            result[2] = 0;
            return result;
        }

        /**
         * 居中对齐
         * 
         * @return
         */
        public static byte[] alignCenter()
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 97;
            result[2] = 1;
            return result;
        }

        /**
         * 右对齐
         * 
         * @return
         */
        public static byte[] alignRight()
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 97;
            result[2] = 2;
            return result;
        }

        /// <summary>
        /// 传送打印机状态
        /// </summary>
        /// <returns></returns>
        public static byte[] transferPrinterStatus()
        {
            byte[] result = new byte[3];
            result[0] = GS;
            result[1] = 114;
            result[2] = 1;
            return result;
        }

        /// <summary>
        /// 允许自动状态回复(ASB)
        /// 允许联机/脱机状态。2
        /// 允许错误状态。4
        /// 允许卷纸传感器状态。8
        /// </summary>
        /// <returns></returns>
        public static byte[] enableAsb()
        {
            byte[] result = new byte[3];
            result[0] = GS;
            result[1] = 97;
            result[2] = 2+4+8;
            return result;
        }

        /**
         * 水平方向向右移动col列
         * 
         * @param col
         * @return
         */
        public static byte[] set_HT_position(byte col)
        {
            byte[] result = new byte[4];
            result[0] = ESC;
            result[1] = 68;
            result[2] = col;
            result[3] = 0;
            return result;
        }

        /// <summary>
        /// 打印并进纸若干个垂直运动单位
        /// </summary>
        /// <param name="col">几个行间距</param>
        /// <returns></returns>
        public static byte[] printAndFeedPaper_VerticalUnit(byte col)
        {
            byte[] result = new byte[4];
            result[0] = ESC;
            result[1] = 74;//100
            result[2] = col;
            return result;
        }
        /// <summary>
        /// 打印并进纸若干个行间距
        /// </summary>
        /// <param name="col">几个行间距</param>
        /// <returns></returns>
        public static byte[] printAndFeedPaper_VertialHjj(byte col)
        {
            byte[] result = new byte[4];
            result[0] = ESC;
            result[1] = 74;//100
            result[2] = col;
            return result;
        }
        /**
         * 字体变大为标准的n倍
         * 
         * @param num
         * @return
         */
        public static byte[] fontSizeSetBig(int num)
        {
            byte realSize = 0;
            switch (num)
            {
                case 1:
                    realSize = 0;
                    break;
                case 2:
                    realSize = 17;
                    break;
                case 3:
                    realSize = 34;
                    break;
                case 4:
                    realSize = 51;
                    break;
                case 5:
                    realSize = 68;
                    break;
                case 6:
                    realSize = 85;
                    break;
                case 7:
                    realSize = 102;
                    break;
                case 8:
                    realSize = 119;
                    break;
            }
            byte[] result = new byte[3];
            result[0] = 29;
            result[1] = 33;
            result[2] = realSize;
            return result;
        }


        /// <summary>
        /// 设置字符字体打印模式
        //0 选择字符字体A (9 × 9
        //1 选择字符字体B(7 × 9
        //0 保留
        //0 没有选择粗体模式。
        //8 选择粗体模式。
        //0 没有选择倍高模式。
        //16 选择倍高模式。
        //0 没有选择倍宽模式。
        //32 选择倍宽模式。
        //0 保留
        //0 没有选择下划线模式。
        //128 选择下划线模式
        /// </summary>
        /// <returns></returns>
        public static byte[] AscFontPrintMode(byte mode)
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 33;
            result[2] = mode;
            return result;
        }
        /// <summary>
        /// 设置多字节编码字符的打印模式
        //0 没有选择倍宽模式。
        //4 选择倍宽模式。
        //0 没有选择倍高模式。
        //8 选择倍高模式。
        //0 保留
        //0 没有选择多字节编码下划
        //128 选择多字节编码下划线。
        /// </summary>
        /// <param name="mode"></param>
        /// <returns></returns>
        public static byte[] MbcsFontPrintMode(byte mode)
        {
            byte[] result = new byte[3];
            result[0] = FS;
            result[1] = 33;
            result[2] = mode;
            return result;
        }

        /**
         * 进纸并全部切割
         * 
         * @return
         */
        public static byte[] feedPaperCutAll()
        {
            byte[] result = new byte[4];
            result[0] = GS;
            result[1] = 86;
            result[2] = 65;
            result[3] = 0;
            return result;
        }

        /**
         * 进纸并切割（左边留一点不切）
         * 
         * @return
         */
        public static byte[] feedPaperCutPartial()
        {
            byte[] result = new byte[4];
            result[0] = GS;
            result[1] = 86;
            result[2] = 66;
            result[3] = 0;
            return result;
        }
        /// <summary>
        /// 每次只能打印四行
        /// </summary>
        /// <param name="m"></param>
        /// <param name="nL">0-255圖像的像素列個數（最多256列）</param>
        /// <param name="nH">0,1,2,3圖像的像素行個數（最多4行）</param>
        /// <returns></returns>
        public static byte[] bitMapPrintHead(byte m,byte nL,byte nH)
        {
            byte[] result = new byte[5+256*nH];
            result[0] = ESC;
            result[1] = 42;
            result[2] = m;
            result[3] = (byte)255;
            result[4] = (byte)(nH-1);
            return result;
        }
        /// <summary>
        /// 缺省行间距
        /// </summary>
        /// <returns></returns>
        public static byte[] defaultVerticalSpace()
        {
            byte[] result = new byte[2];
            result[0] = ESC;
            result[1] = 50;
            return result;
        }

        /// <summary>
        /// 图像打印行间距 n=24 1/6 英寸 默认值
        /// </summary>
        /// <returns></returns>
        public static byte[] bitMapVerticalSpace(byte n)
        {
            byte[] result = new byte[3];
            result[0] = ESC;
            result[1] = 3;
            result[2] = n;
            return result;
        }




        /// <summary>
        /// 把一张32X256 Bitmap图片转化为打印机可以打印的bit
        /// </summary>
        /// <param name="bit"></param>
        /// <returns></returns>
        public static byte[] pic2PxPoint(Bitmap bit)
        {
            //最多256列，最多4行，每個字節表示8個像素
            //tm-u220圖形打印模式是點單密度
            int x1 = bit.Width;
            int y1 = bit.Height;
            int heightPixels = 24;
            int widthPixels = 256;
            byte[] data = new byte[(256+6)*3];
            int k = 0;
            //4行，每個字節可以保持8個黑白像素的數據，所以總共可以保存位圖32行的像素數據
            data[0] = 0x1B;
            data[1] = 0x2A;
            data[2] = 0; // m=0 选择8点單密度打印，每列可以打印8個點。
            byte tmu220Width = 198;
            data[3] = tmu220Width;//198列
            data[4] = 1;//4行
            k = 4;
            for (int j = 0; j < 2; j++)
            {
                for (int i = 0; i < tmu220Width+1; i++)
                {
                    k++;
                    byte[] by = new byte[8];
                    for (int n = 0; n < 8; n++)
                    {
                        byte b = px2Byte(i, j * 8 +7-n, bit);
                        if (i > 198) b = 0;
                        by[n] = b;
                    }
                    data[k] = (byte)changePointPx1(by);                    
                }
            }
            return data;
        }
        public static byte[] pic2PxPoint(Bitmap bit,int rowIndex)
        {
            //最多256列，最多4行，每個字節表示8個像素
            //tm-u220圖形打印模式是點單密度
            int x1 = bit.Width;
            int y1 = bit.Height;
            int heightPixels = bit.Height;
            int widthPixels = bit.Width;
            byte nL = 128;
            byte nH = 1;
            byte[] data = new byte[nL+nL*(nH+1)+5];
            for (int i = 0; i < 128 * 3 + 5; i++) data[i] = 0;
            int k = 0;
            //4行，每個字節可以保持8個黑白像素的數據，所以總共可以保存位圖32行的像素數據
            data[0] = 0x1B;
            data[1] = 0x2A;
            data[2] = 1; // m=0 选择8点單密度打印，每列可以打印8個點。
            byte tmu220Width = 200;
            data[3] = (byte)(widthPixels%255);// tmu220Width;//200列
            data[4] = 1;//4行 对于tm-u220虽然图形模式只支持8点，但是数据需要以24点阵进行准备
            //k = 4;
            for (int i= 0; i < widthPixels; i++)
            {
                for (int j = rowIndex; j < rowIndex+1; j++)
                {
                    if (i < 128)
                    {
                        byte[] by = new byte[8];
                        for (int n = 0; n < 8; n++)
                        {
                            byte b = 0;
                            b = px2Byte(i, j * 8 + 7 - n, bit);
                            by[n] = b;
                        }
                        //data[i + j * 128 + 5] = (byte)changePointPx1(by);
                        data[i + 5] = (byte)changePointPx1(by);
                    }                    
                }
            }
            return data;
        }
        public static byte[] pic2PxPointTest(Bitmap bit, int rowIndex)
        {
            //最多256列，最多4行，每個字節表示8個像素
            //tm-u220圖形打印模式是點單密度
            int heightPixels = bit.Height;
            int widthPixels = bit.Width;
            byte nL = (byte)(widthPixels-256);
            byte nH = 1;
            int dataByteArraySize = (nH + 1) * 256 + 5;
            byte[] data = new byte[nL + nL * (nH + 1) + 5];
            for (int i = 0; i < 128 * 3 + 5; i++) data[i] = 0;
            int k = 0;
            //4行，每個字節可以保持8個黑白像素的數據，所以總共可以保存位圖32行的像素數據
            data[0] = 0x1B;
            data[1] = 0x2A;
            //m=0 8点单密度默认边距条件下,可以打印像素宽度为200以内的图片
            //m=1 8点双密度默认边距条件下,可以打印像素宽度为400以内的图片
            data[2] = 0; // m=0 选择8点单密度打印，每列可以打印8個點。
            data[3] = nL;// tmu220Width;//200列
            data[4] = nH;//4行 对于tm-u220虽然图形模式只支持8点，但是数据需要以24点阵进行准备
            //k = 4;
            for (int i = 0; i < widthPixels; i++)
            {
                for (int j = rowIndex; j < rowIndex + 1; j++)
                {
                    if (i < widthPixels)
                    {
                        byte[] by = new byte[8];
                        for (int n = 0; n < 8; n++)
                        {
                            byte b = 0;
                            b = px2Byte(i, j * 8 + 7 - n, bit);
                            by[n] = b;
                        }
                        data[i + 5] = (byte)changePointPx1(by);
                    }
                }
            }
            return data;
        }
        /// <summary>
        /// 8点单密度 
        /// //tm-u220圖形打印模式是8點單密度
            //位图的宽和高，宽度固定为200，高度应为8的整数倍
        /// </summary>
        /// <param name="bit">位图</param>
        /// <param name="rowIndex">8像素高度为一条水平扫描线，第几条薯片扫描线，从top第一条水平扫描线为0</param>
        /// <returns></returns>
        public static byte[] pic2PxPoint8NeedleSingleDensity(Bitmap bit, int rowIndex)
        {
            
            int heightPixels = bit.Height;
            int widthPixels = bit.Width;
            byte nL = (byte)(widthPixels - 256);
            byte nH = 1;
            int dataByteArraySize = (nH + 1) * 256 + 5;
            byte[] data = new byte[nL + nL * (nH + 1) + 5];
            for (int i = 0; i < 128 * 3 + 5; i++) data[i] = 0;
            data[0] = 0x1B;
            data[1] = 0x2A;
            //m=0 8点单密度默认边距条件下,可以打印像素宽度为200以内的图片
            //m=1 8点双密度默认边距条件下,可以打印像素宽度为400以内的图片
            data[2] = 1; // m=1 选择8点双密度打印，每列可以打印8個點。
            data[3] = nL;// tmu220Width;//200列
            data[4] = nH;//4行 对于tm-u220虽然图形模式只支持8点，但是数据需要以24点阵进行准备
            //k = 4;
            for (int i = 0; i < widthPixels; i++)
            {
                for (int j = rowIndex; j < rowIndex + 1; j++)
                {
                    if (i < widthPixels)
                    {
                        byte[] by = new byte[8];
                        for (int n = 0; n < 8; n++)
                        {
                            byte b = 0;
                            b = px2Byte(i, j * 8 + 7 - n, bit);
                            by[n] = b;
                        }
                        data[i + 5] = (byte)changePointPx1(by);
                    }
                }
            }
            return data;
        }
        /// <summary>
        /// 8点双密度
        /// tm-u220圖形打印模式是8點双密度
        /// 位图的宽和高，宽度固定为400，高度应为8的整数倍
        /// </summary>
        /// <param name="bit">位图</param>
        /// <param name="rowIndex">8像素高度为一条水平扫描线，第几条薯片扫描线，从0开始</param>
        /// <returns></returns>
        public static byte[] pic2PxPoint8NeedleDoubleDensity(Bitmap bit, int rowIndex)
        {
            //最多256列，最多4行，每個字節表示8個像素
            //tm-u220圖形打印模式是點單密度
            int heightPixels = bit.Height;
            int widthPixels = bit.Width;
            byte nL = (byte)(widthPixels - 256);
            byte nH = 1;
            int dataByteArraySize = (nH + 1) * 256 + 5;
            byte[] data = new byte[nL + nL * (nH + 1) + 5];
            for (int i = 0; i < 128 * 3 + 5; i++) data[i] = 0;
            int k = 0;
            //4行，每個字節可以保持8個黑白像素的數據，所以總共可以保存位圖32行的像素數據
            data[0] = 0x1B;
            data[1] = 0x2A;
            //m=0 8点单密度默认边距条件下,可以打印像素宽度为200以内的图片
            //m=1 8点双密度默认边距条件下,可以打印像素宽度为400以内的图片
            data[2] = 1; // m=1 选择8点双密度打印，每列可以打印8個點。
            data[3] = nL;// tmu220Width;//200列
            data[4] = nH;//4行 对于tm-u220虽然图形模式只支持8点，但是数据需要以24点阵进行准备
            //k = 4;
            for (int i = 0; i < widthPixels; i++)
            {
                for (int j = rowIndex; j < rowIndex + 1; j++)
                {
                    if (i < widthPixels)
                    {
                        byte[] by = new byte[8];
                        for (int n = 0; n < 8; n++)
                        {
                            byte b = 0;
                            b = px2Byte(i, j * 8 + 7 - n, bit);
                            by[n] = b;
                        }
                        data[i + 5] = (byte)changePointPx1(by);
                    }
                }
            }
            return data;
        }


        /// <summary>
        /// 将[1,0,0,1,0,0,0,1]这样的二进制转为化十进制的数值（效率更高）
        /// </summary>
        /// <param name="arry"></param>
        /// <returns></returns>
        public static int changePointPx1(byte[] arry)
        {
            int v = 0;
            for (int j = 0; j < arry.Length; j++)
            {
                if (arry[j] == 1)
                {
                    v = v | 1 << j;
                }
            }
            return v;
        }
        /// <summary>
        ///图片二值化，黑色是1，白色是0
        /// </summary>
        /// <param name="x">横坐标</param>
        /// <param name="y">纵坐标</param>
        /// <param name="bit">位图</param>
        /// <returns></returns>
        public static byte px2Byte(int x, int y, Bitmap bitmap)
        {
            byte b;
            Color pixel = bitmap.GetPixel(x, y);
            int gray = RGB2Gray(pixel.R, pixel.G,pixel.B);
            if (gray < 128)
            {
                b = 1;
            }
            else
            {
                b = 0;
            }
            return b;
        }

        /// <summary>
        /// 图片灰度的转化      /**
     /// </summary>
     /// <param name="r"></param>
     /// <param name="g"></param>
     /// <param name="b"></param>
     /// <returns></returns>
        private static int RGB2Gray(int r, int g, int b)
        {
            int gray = (int)(0.29900 * r + 0.58700 * g + 0.11400 * b);  //灰度转化公式
            return gray;
        }

        // ------------------------切纸-----------------------------
        public static byte[] byteMerger(byte[] byte_1, byte[] byte_2)
        {
            byte[] byte_3 = new byte[byte_1.Length + byte_2.Length];
            System.Array.Copy(byte_1, 0, byte_3, 0, byte_1.Length);
            System.Array.Copy(byte_2, 0, byte_3, byte_1.Length, byte_2.Length);
            return byte_3;
        }

        public static byte[] byteMerger(byte[][] byteList)
        {
            int Length = 0;
            for (int i = 0; i < byteList.Length; i++)
            {
                Length += byteList[i].Length;
            }
            byte[] result = new byte[Length];

            int index = 0;
            for (int i = 0; i < byteList.Length; i++)
            {
                byte[] nowByte = byteList[i];
                for (int k = 0; k < byteList[i].Length; k++)
                {
                    result[index] = nowByte[k];
                    index++;
                }
            }
            return result;
        }

        public static byte[][] byte20Merger(byte[] bytes)
        {
            int size = bytes.Length / 10 + 1;
            byte[][] result = new byte[size][];
            for (int i = 0; i < size; i++)
            {
                byte[] by = new byte[((i + 1) * 10) - (i * 10)];
                //从bytes中的第 i * 10 个位置到第 (i + 1) * 10 个位置;
                System.Array.Copy(bytes, i * 10, by, 0, (i + 1) * 10);
                result[i] = by;
            }
            return result;
        }
    }
}
